package com.um2.simplexe.serveur.ui.util.controleUI.chargeur;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Vector;
import java.util.jar.JarFile;

import com.um2.simplexe.serveur.ui.util.controleUI.InformationsSurApplicationServeur;


/**
 * Classe gerant le chargement et la validation des plugins
 * @author Laine Vincent (dev01, http://vincentlaine.developpez.com/ )
 * 
 * adapte pour le simlexe: Jean-Marie Codol
 *
 */
public class ChargeurLibrairie {

	/**
	 * les fichiers .
	 */
	private String[] files;
	
	/**
	 * les classes quand il y en aura besoin
	 */
	private ArrayList classPlugins;
	
	
	
	/**
	 * Constructeur par defaut
	 *
	 */
	public ChargeurLibrairie() {
		this.classPlugins = new ArrayList();
	}
	
	
	/**
	 * Defini l'ensemble des fichiers e charger
	 * @param files
	 */
	public void setFiles(String[] files){
		this.files = files;
	}
	
	
	
	/**
	 * Fonction de chargement de tout les plugins de type StringPlugins
	 * @return Une collection de StringPlugins contenant les instances des plugins
	 * @throws Exception si file = null ou file.length = 0
	 */
	public void chargerToutLesPlugins() throws Exception {
		
		try {
			this.initializeLoader();
		} catch (Exception e) {
			throw new Exception("impossible d'initialiser le chargeur \n"+e.getMessage()+"\n (ChargeurDePlugins.ChargerToutLesPlugins())");
		}
	}
	
	
	
	
	// ici il y a un forname,
	// donc theoriquement on est bon.
	@SuppressWarnings({ "unchecked", "deprecation" })
	private void initializeLoader() throws Exception {
		
		
		// on filtre ici les .jar et les non .jar.
		Vector<String> filesFinal = new Vector<String>() ;
		for (String s : this.files) {
			if (new File(s).isDirectory())
			{
				// est un repertoire
			}else
			{
				// est un fichier
				if (new File(s).getName().endsWith(".jar"))
				{
					// l'extention est .jar
					filesFinal.add(s) ;
				}else
				{
					// l'extention n'est pas .jar				
				}
			}
		}
		
		
		for (String nomJar : filesFinal) {
			InformationsSurApplicationServeur.listePluginsChargeurDeLibrairiesPartagees.add(nomJar) ;
		}
		
		
		this.files = new String[filesFinal.size()] ;
		int indice=0 ;
		for (String s : filesFinal) {
			this.files[indice] = s ;
			indice++ ;
		}
		
		
		//On verifie que la liste des plugins e charger e ete initialise
		if(this.files == null || this.files.length == 0 ){
			// Pas de fichier renseignes pour faire des plugins
			return ;
		}

		//Pour eviter le double chargement des plugins
		// on ne veut pas pouvoir charger 2 fois les plugins.
		if(this.classPlugins.size() != 0 ){
			throw new Exception("les plugins ont dejas etes charges\n");
		}
		
		File[] f = new File[this.files.length];
		//Pour charger le .jar en memoire
		URLClassLoader loader;
		//Pour la comparaison de chaines
		String tmp = "";
		//Pour le contenu de l'archive jar
		Enumeration enumeration;
		//Pour determine quels sont les interfaces implementees
		Class tmpClass = null;
		
		for(int index = 0 ; index < f.length ; index ++ ){
			
			f[index] = new File(this.files[index]);
			
			if( !f[index].exists() ) {
				System.err.println("le fichier librairie "+this.files[index]+" n'existe pas\n   => on continue sur la librairie suivante.");
				break;
			}
			
			URL u;
			try {
				u = f[index].toURL();
			} catch (MalformedURLException e) {
				throw new Exception("l'URL demandee pour la librairie ( "+f[index]+" ) est mal formee :\n"+e.getMessage()) ;
			}
			//On creer un nouveau URLClassLoader pour charger le jar qui se trouve ne dehors du CLASSPATH
			loader = new URLClassLoader(new URL[] {u}); 
			
			
			//On charge le jar en memoire
			JarFile jar;
			try {
				jar = new JarFile(f[index].getAbsolutePath());
			} catch (IOException e) {
				throw new Exception("erreur pendant le chargement de la librairie :\n   ("+f[index].getAbsolutePath()+")\n :: le .jar n'est pas une archive jar valide !:\n IOException :\n"+e.getMessage()) ;
			}
			
			//On recupere le contenu du jar
			enumeration = jar.entries();
			
			while(enumeration.hasMoreElements()){
				tmp = enumeration.nextElement().toString();

				//On verifie que le fichier courant est un .class (et pas un fichier d'informations du jar )
				if(tmp.length() > 6 && tmp.substring(tmp.length()-6).compareTo(".class") == 0) {
					
					tmp = tmp.substring(0,tmp.length()-6);
					tmp = tmp.replaceAll("/",".");
					
					try {
						tmpClass = Class.forName(tmp ,true,loader);
					} catch (ClassNotFoundException e) {
						throw new Exception("La classe a l'interieur du plugin n'a pas ete trouvee :\n "+e.getMessage()) ;
					}
					
					for(int i = 0 ; i < tmpClass.getInterfaces().length; i ++ ){
						
						//Une classe ne doit pas appartenir e deux categories de plugins differents. 
						//Si tel est le cas on ne la place que dans la categorie de la premiere interface correcte
						// trouvee
//						if(tmpClass.getInterfaces()[i].getName().toString().equals(InformationsSurApplication.INTERFACE_CONTROLE_MENU) ) {
							this.classPlugins.add(tmpClass);
//						}
					}
					
				}else
				{
					// le fichier tmp n'est pas une classe java 
				}
			}
			
		
		}
		
	}
	
	
}
